home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / more / RCS / more.c,v < prev   
Text File  |  1989-12-10  |  37KB  |  1,956 lines

  1. head     1.5;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.5
  10. date     89.12.09.21.23.54;  author mendel;  state Exp;
  11. branches ;
  12. next     1.4;
  13.  
  14. 1.4
  15. date     89.05.30.17.48.32;  author shirriff;  state Exp;
  16. branches ;
  17. next     1.3;
  18.  
  19. 1.3
  20. date     88.09.12.13.47.12;  author mendel;  state Exp;
  21. branches ;
  22. next     1.2;
  23.  
  24. 1.2
  25. date     88.09.11.16.53.42;  author ouster;  state Exp;
  26. branches ;
  27. next     1.1;
  28.  
  29. 1.1
  30. date     88.07.21.16.00.31;  author ouster;  state Exp;
  31. branches ;
  32. next     ;
  33.  
  34.  
  35. desc
  36. @@
  37.  
  38.  
  39. 1.5
  40. log
  41. @Fixed varargs stuff to work on sun4.
  42. @
  43. text
  44. @/*
  45.  * Copyright (c) 1980 Regents of the University of California.
  46.  * All rights reserved.
  47.  *
  48.  * Redistribution and use in source and binary forms are permitted
  49.  * provided that this notice is preserved and that due credit is given
  50.  * to the University of California at Berkeley. The name of the University
  51.  * may not be used to endorse or promote products derived from this
  52.  * software without specific written prior permission. This software
  53.  * is provided ``as is'' without express or implied warranty.
  54.  */
  55.  
  56. #ifndef lint
  57. char copyright[] =
  58. "@@(#) Copyright (c) 1980 Regents of the University of California.\n\
  59.  All rights reserved.\n";
  60. #endif /* not lint */
  61.  
  62. #ifndef lint
  63. static char sccsid[] = "@@(#)more.c    5.18 (Berkeley) 4/25/88";
  64. #endif /* not lint */
  65.  
  66. /*
  67. ** more.c - General purpose tty output filter and file perusal program
  68. **
  69. **    by Eric Shienbrood, UC Berkeley
  70. **
  71. **    modified by Geoff Peck, UCB to add underlining, single spacing
  72. **    modified by John Foderaro, UCB to add -c and MORE environment variable
  73. */
  74.  
  75. #include <stdio.h>
  76. #include <sys/param.h>
  77. #include <ctype.h>
  78. #include <signal.h>
  79. #include <errno.h>
  80. #include <sgtty.h>
  81. #include <setjmp.h>
  82. #include <sys/stat.h>
  83. #include <sys/file.h>
  84. #include <a.out.h>
  85. #include <varargs.h>
  86.  
  87. #define HELPFILE    "/sprite/lib/more/more.help"
  88. #define VI        "/sprite/cmds/vi"
  89.  
  90. #define Fopen(s,m)    (Currline = 0,file_pos=0,fopen(s,m))
  91. #define Ftell(f)    file_pos
  92. #define Fseek(f,off)    (file_pos=off,fseek(f,off,0))
  93. #define Getc(f)        (++file_pos, getc(f))
  94. #define Ungetc(c,f)    (--file_pos, ungetc(c,f))
  95.  
  96. #define MBIT    CBREAK
  97. #define stty(fd,argp)    ioctl(fd,TIOCSETN,argp)
  98.  
  99. #define TBUFSIZ    1024
  100. #define LINSIZ    256
  101. #define ctrl(letter)    (letter & 077)
  102. #define RUBOUT    '\177'
  103. #define ESC    '\033'
  104. #define QUIT    '\034'
  105.  
  106. struct sgttyb    otty, savetty;
  107. long        file_pos, file_size;
  108. int        fnum, no_intty, no_tty, slow_tty;
  109. int        dum_opt, dlines, onquit(), end_it(), chgwinsz();
  110. int        onsusp();
  111. int        nscroll = 11;    /* Number of lines scrolled by 'd' */
  112. int        fold_opt = 1;    /* Fold long lines */
  113. int        stop_opt = 1;    /* Stop after form feeds */
  114. int        ssp_opt = 0;    /* Suppress white space */
  115. int        ul_opt = 1;    /* Underline as best we can */
  116. int        promptlen;
  117. int        Currline;    /* Line we are currently at */
  118. int        startup = 1;
  119. int        firstf = 1;
  120. int        notell = 1;
  121. int        docrterase = 0;
  122. int        docrtkill = 0;
  123. int        bad_so;    /* True if overwriting does not turn off standout */
  124. int        inwait, Pause, errors;
  125. int        within;    /* true if we are within a file,
  126.             false if we are between files */
  127. int        hard, dumb, noscroll, hardtabs, clreol, eatnl;
  128. int        catch_susp;    /* We should catch the SIGTSTP signal */
  129. char        **fnames;    /* The list of file names */
  130. int        nfiles;        /* Number of files left to process */
  131. char        *shell;        /* The name of the shell to use */
  132. int        shellp;        /* A previous shell command exists */
  133. char        ch;
  134. jmp_buf        restore;
  135. char        Line[LINSIZ];    /* Line buffer */
  136. int        Lpp = 24;    /* lines per page */
  137. char        *Clear;        /* clear screen */
  138. char        *eraseln;    /* erase line */
  139. char        *Senter, *Sexit;/* enter and exit standout mode */
  140. char        *ULenter, *ULexit;    /* enter and exit underline mode */
  141. char        *chUL;        /* underline character */
  142. char        *chBS;        /* backspace character */
  143. char        *Home;        /* go to home */
  144. char        *cursorm;    /* cursor movement */
  145. char        cursorhome[40];    /* contains cursor movement to home */
  146. char        *EodClr;    /* clear rest of screen */
  147. char        *tgetstr();
  148. int        Mcol = 80;    /* number of columns */
  149. int        Wrap = 1;    /* set if automargins */
  150. int        soglitch;    /* terminal has standout mode glitch */
  151. int        ulglitch;    /* terminal has underline mode glitch */
  152. int        pstate = 0;    /* current UL state */
  153. long        fseek();
  154. char        *getenv();
  155. struct {
  156.     long chrctr, line;
  157. } context, screen_start;
  158. extern char    PC;        /* pad character */
  159. extern short    ospeed;
  160.  
  161. /*
  162.  * Forward declarations, to keep gcc happy:
  163.  */
  164.  
  165. extern int magic();
  166.  
  167. main(argc, argv)
  168. int argc;
  169. char *argv[];
  170. {
  171.     register FILE    *f;
  172.     register char    *s;
  173.     register char    *p;
  174.     register char    ch;
  175.     register int    left;
  176.     int            prnames = 0;
  177.     int            initopt = 0;
  178.     int            srchopt = 0;
  179.     int            clearit = 0;
  180.     int            initline;
  181.     char        initbuf[80];
  182.     FILE        *checkf();
  183.  
  184.     nfiles = argc;
  185.     fnames = argv;
  186.     initterm ();
  187.     nscroll = Lpp/2 - 1;
  188.     if (nscroll <= 0)
  189.     nscroll = 1;
  190.     if(s = getenv("MORE")) argscan(s);
  191.     while (--nfiles > 0) {
  192.     if ((ch = (*++fnames)[0]) == '-') {
  193.         argscan(*fnames+1);
  194.     }
  195.     else if (ch == '+') {
  196.         s = *fnames;
  197.         if (*++s == '/') {
  198.         srchopt++;
  199.         for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
  200.             *p++ = *s++;
  201.         *p = '\0';
  202.         }
  203.         else {
  204.         initopt++;
  205.         for (initline = 0; *s != '\0'; s++)
  206.             if (isdigit (*s))
  207.             initline = initline*10 + *s -'0';
  208.         --initline;
  209.         }
  210.     }
  211.     else break;
  212.     }
  213.     /* allow clreol only if Home and eraseln and EodClr strings are
  214.      *  defined, and in that case, make sure we are in noscroll mode
  215.      */
  216.     if(clreol)
  217.     {
  218.         if((Home == NULL) || (*Home == '\0') ||
  219.        (eraseln == NULL) || (*eraseln == '\0') ||
  220.            (EodClr == NULL) || (*EodClr == '\0') )
  221.           clreol = 0;
  222.     else noscroll = 1;
  223.     }
  224.     if (dlines == 0)
  225.     dlines = Lpp - (noscroll ? 1 : 2);
  226.     left = dlines;
  227.     if (nfiles > 1)
  228.     prnames++;
  229.     if (!no_intty && nfiles == 0) {
  230.     char *rindex();
  231.  
  232.     p = rindex(argv[0], '/');
  233.     fputs("usage: ",stderr);
  234.     fputs(p ? p + 1 : argv[0],stderr);
  235.     fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
  236.     exit(1);
  237.     }
  238.     else
  239.     f = stdin;
  240.     if (!no_tty) {
  241.     signal(SIGQUIT, onquit);
  242.     signal(SIGINT, end_it);
  243.     signal(SIGWINCH, chgwinsz);
  244.     if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
  245.         signal(SIGTSTP, onsusp);
  246.         catch_susp++;
  247.     }
  248.     stty (fileno(stderr), &otty);
  249.     }
  250.     if (no_intty) {
  251.     if (no_tty)
  252.         copy_file (stdin);
  253.     else {
  254.         if ((ch = Getc (f)) == '\f')
  255.         doclear();
  256.         else {
  257.         Ungetc (ch, f);
  258.         if (noscroll && (ch != EOF)) {
  259.             if (clreol)
  260.             home ();
  261.             else
  262.             doclear ();
  263.         }
  264.         }
  265.         if (srchopt)
  266.         {
  267.         search (initbuf, stdin, 1);
  268.         if (noscroll)
  269.             left--;
  270.         }
  271.         else if (initopt)
  272.         skiplns (initline, stdin);
  273.         screen (stdin, left);
  274.     }
  275.     no_intty = 0;
  276.     prnames++;
  277.     firstf = 0;
  278.     }
  279.  
  280.     while (fnum < nfiles) {
  281.     if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
  282.         context.line = context.chrctr = 0;
  283.         Currline = 0;
  284.         if (firstf) setjmp (restore);
  285.         if (firstf) {
  286.         firstf = 0;
  287.         if (srchopt)
  288.         {
  289.             search (initbuf, f, 1);
  290.             if (noscroll)
  291.             left--;
  292.         }
  293.         else if (initopt)
  294.             skiplns (initline, f);
  295.         }
  296.         else if (fnum < nfiles && !no_tty) {
  297.         setjmp (restore);
  298.         left = command (fnames[fnum], f);
  299.         }
  300.         if (left != 0) {
  301.         if ((noscroll || clearit) && (file_size != LONG_MAX))
  302.             if (clreol)
  303.             home ();
  304.             else
  305.             doclear ();
  306.         if (prnames) {
  307.             if (bad_so)
  308.             erase (0);
  309.             if (clreol)
  310.             cleareol ();
  311.             pr("::::::::::::::");
  312.             if (promptlen > 14)
  313.             erase (14);
  314.             printf ("\n");
  315.             if(clreol) cleareol();
  316.             printf("%s\n", fnames[fnum]);
  317.             if(clreol) cleareol();
  318.             printf("::::::::::::::\n");
  319.             if (left > Lpp - 4)
  320.             left = Lpp - 4;
  321.         }
  322.         if (no_tty)
  323.             copy_file (f);
  324.         else {
  325.             within++;
  326.             screen(f, left);
  327.             within = 0;
  328.         }
  329.         }
  330.         setjmp (restore);
  331.         fflush(stdout);
  332.         fclose(f);
  333.         screen_start.line = screen_start.chrctr = 0L;
  334.         context.line = context.chrctr = 0L;
  335.     }
  336.     fnum++;
  337.     firstf = 0;
  338.     }
  339.     reset_tty ();
  340.     exit(0);
  341. }
  342.  
  343. argscan(s)
  344. char *s;
  345. {
  346.     int seen_num = 0;
  347.  
  348.     while (*s != '\0') {
  349.         switch (*s) {
  350.           case '0': case '1': case '2':
  351.           case '3': case '4': case '5':
  352.           case '6': case '7': case '8':
  353.           case '9':
  354.             if (!seen_num) {
  355.                 dlines = 0;
  356.                 seen_num = 1;
  357.             }
  358.             dlines = dlines*10 + *s - '0';
  359.             break;
  360.           case 'd':
  361.             dum_opt = 1;
  362.             break;
  363.           case 'l':
  364.             stop_opt = 0;
  365.             break;
  366.           case 'f':
  367.             fold_opt = 0;
  368.             break;
  369.           case 'p':
  370.             noscroll++;
  371.             break;
  372.           case 'c':
  373.             clreol++;
  374.             break;
  375.           case 's':
  376.             ssp_opt = 1;
  377.             break;
  378.           case 'u':
  379.             ul_opt = 0;
  380.             break;
  381.         }
  382.         s++;
  383.     }
  384. }
  385.  
  386.  
  387. /*
  388. ** Check whether the file named by fs is an ASCII file which the user may
  389. ** access.  If it is, return the opened file. Otherwise return NULL.
  390. */
  391.  
  392. FILE *
  393. checkf (fs, clearfirst)
  394.     register char *fs;
  395.     int *clearfirst;
  396. {
  397.     struct stat stbuf;
  398.     register FILE *f;
  399.     char c;
  400.  
  401.     if (stat (fs, &stbuf) == -1) {
  402.         (void)fflush(stdout);
  403.         if (clreol)
  404.             cleareol ();
  405.         perror(fs);
  406.         return((FILE *)NULL);
  407.     }
  408.     if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
  409.         printf("\n*** %s: directory ***\n\n", fs);
  410.         return((FILE *)NULL);
  411.     }
  412.     if ((f = Fopen(fs, "r")) == NULL) {
  413.         (void)fflush(stdout);
  414.         perror(fs);
  415.         return((FILE *)NULL);
  416.     }
  417.     if (magic(f, fs))
  418.         return((FILE *)NULL);
  419.     c = Getc(f);
  420.     *clearfirst = c == '\f';
  421.     Ungetc (c, f);
  422.     if ((file_size = stbuf.st_size) == 0)
  423.         file_size = LONG_MAX;
  424.     return(f);
  425. }
  426.  
  427. /*
  428.  * magic --
  429.  *    check for file magic numbers.  This code would best be shared with
  430.  *    the file(1) program or, perhaps, more should not try and be so smart?
  431.  */
  432. static
  433. magic(f, fs)
  434.     FILE *f;
  435.     char *fs;
  436. {
  437.     struct exec ex;
  438.  
  439.     if (fread(&ex, sizeof(ex), 1, f) == 1)
  440.         switch(ex.a_magic) {
  441.         case OMAGIC:
  442.         case NMAGIC:
  443.         case ZMAGIC:
  444.         case 0405:
  445.         case 0411:
  446.         case 0177545:
  447.             printf("\n******** %s: Not a text file ********\n\n", fs);
  448.             (void)fclose(f);
  449.             return(1);
  450.         }
  451.     (void)fseek(f, 0L, L_SET);        /* rewind() not necessary */
  452.     return(0);
  453. }
  454.  
  455. /*
  456. ** A real function, for the tputs routine in termlib
  457. */
  458.  
  459. putch (ch)
  460. char ch;
  461. {
  462.     putchar (ch);
  463. }
  464.  
  465. /*
  466. ** Print out the contents of the file f, one screenful at a time.
  467. */
  468.  
  469. #define STOP -10
  470.  
  471. screen (f, num_lines)
  472. register FILE *f;
  473. register int num_lines;
  474. {
  475.     register int c;
  476.     register int nchars;
  477.     int length;            /* length of current line */
  478.     static int prev_len = 1;    /* length of previous line */
  479.  
  480.     for (;;) {
  481.     while (num_lines > 0 && !Pause) {
  482.         if ((nchars = getline (f, &length)) == EOF)
  483.         {
  484.         if (clreol)
  485.             clreos();
  486.         return;
  487.         }
  488.         if (ssp_opt && length == 0 && prev_len == 0)
  489.         continue;
  490.         prev_len = length;
  491.         if (bad_so || (Senter && *Senter == ' ') && promptlen > 0)
  492.         erase (0);
  493.         /* must clear before drawing line since tabs on some terminals
  494.          * do not erase what they tab over.
  495.          */
  496.         if (clreol)
  497.         cleareol ();
  498.         prbuf (Line, length);
  499.         if (nchars < promptlen)
  500.         erase (nchars);    /* erase () sets promptlen to 0 */
  501.         else promptlen = 0;
  502.         /* is this needed?
  503.          * if (clreol)
  504.          *    cleareol();    /* must clear again in case we wrapped *
  505.          */
  506.         if (nchars < Mcol || !fold_opt)
  507.         prbuf("\n", 1);    /* will turn off UL if necessary */
  508.         if (nchars == STOP)
  509.         break;
  510.         num_lines--;
  511.     }
  512.     if (pstate) {
  513.         tputs(ULexit, 1, putch);
  514.         pstate = 0;
  515.     }
  516.     fflush(stdout);
  517.     if ((c = Getc(f)) == EOF)
  518.     {
  519.         if (clreol)
  520.         clreos ();
  521.         return;
  522.     }
  523.  
  524.     if (Pause && clreol)
  525.         clreos ();
  526.     Ungetc (c, f);
  527.     setjmp (restore);
  528.     Pause = 0; startup = 0;
  529.     if ((num_lines = command (NULL, f)) == 0)
  530.         return;
  531.     if (hard && promptlen > 0)
  532.         erase (0);
  533.     if (noscroll && num_lines >= dlines)
  534.     {
  535.         if (clreol)
  536.         home();
  537.         else
  538.         doclear ();
  539.     }
  540.     screen_start.line = Currline;
  541.     screen_start.chrctr = Ftell (f);
  542.     }
  543. }
  544.  
  545. /*
  546. ** Come here if a quit signal is received
  547. */
  548.  
  549. onquit()
  550. {
  551.     signal(SIGQUIT, SIG_IGN);
  552.     if (!inwait) {
  553.     putchar ('\n');
  554.     if (!startup) {
  555.         signal(SIGQUIT, onquit);
  556.         longjmp (restore, 1);
  557.     }
  558.     else
  559.         Pause++;
  560.     }
  561.     else if (!dum_opt && notell) {
  562.     write (2, "[Use q or Q to quit]", 20);
  563.     promptlen += 20;
  564.     notell = 0;
  565.     }
  566.     signal(SIGQUIT, onquit);
  567. }
  568.  
  569. /*
  570. ** Come here if a signal for a window size change is received
  571. */
  572.  
  573. chgwinsz()
  574. {
  575.     struct winsize win;
  576.  
  577.     (void) signal(SIGWINCH, SIG_IGN);
  578.     if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
  579.     if (win.ws_row != 0) {
  580.         Lpp = win.ws_row;
  581.         nscroll = Lpp/2 - 1;
  582.         if (nscroll <= 0)
  583.         nscroll = 1;
  584.         dlines = Lpp - (noscroll ? 1 : 2);
  585.     }
  586.     if (win.ws_col != 0)
  587.         Mcol = win.ws_col;
  588.     }
  589.     (void) signal(SIGWINCH, chgwinsz);
  590. }
  591.  
  592. /*
  593. ** Clean up terminal state and exit. Also come here if interrupt signal received
  594. */
  595.  
  596. end_it ()
  597. {
  598.  
  599.     reset_tty ();
  600.     if (clreol) {
  601.     putchar ('\r');
  602.     clreos ();
  603.     fflush (stdout);
  604.     }
  605.     else if (!clreol && (promptlen > 0)) {
  606.     kill_line ();
  607.     fflush (stdout);
  608.     }
  609.     else
  610.     write (2, "\n", 1);
  611.     _exit(0);
  612. }
  613.  
  614. copy_file(f)
  615. register FILE *f;
  616. {
  617.     register int c;
  618.  
  619.     while ((c = getc(f)) != EOF)
  620.     putchar(c);
  621. }
  622.  
  623. /* Simplified printf function */
  624.  
  625. printf (va_alist)
  626. va_dcl
  627. {
  628.     va_list ap;
  629.     register char ch;
  630.     register int ccount;
  631.     register char *fmt;
  632.  
  633.     ccount = 0;
  634.     va_start(ap);
  635.     fmt = va_arg(ap, char *);
  636.     while (*fmt) {
  637.         while ((ch = *fmt++) != '%') {
  638.             if (ch == '\0')
  639.                 return (ccount);
  640.             ccount++;
  641.             putchar (ch);
  642.         }
  643.         switch (*fmt++) {
  644.         case 'd':
  645.             ccount += printd (va_arg(ap, int));
  646.             break;
  647.         case 's':
  648.             ccount += pr (va_arg(ap, char *));
  649.             break;
  650.         case '%':
  651.             ccount++;
  652.             putchar ('%');
  653.             break;
  654.         case '0':
  655.             return (ccount);
  656.         default:
  657.             break;
  658.         }
  659.     }
  660.     va_end(ap);
  661.     return (ccount);
  662.  
  663. }
  664.  
  665. /*
  666. ** Print an integer as a string of decimal digits,
  667. ** returning the length of the print representation.
  668. */
  669.  
  670. printd (n)
  671. int n;
  672. {
  673.     int a, nchars;
  674.  
  675.     if (a = n/10)
  676.     nchars = 1 + printd(a);
  677.     else
  678.     nchars = 1;
  679.     putchar (n % 10 + '0');
  680.     return (nchars);
  681. }
  682.  
  683. /* Put the print representation of an integer into a string */
  684. static char *sptr;
  685.  
  686. scanstr (n, str)
  687. int n;
  688. char *str;
  689. {
  690.     sptr = str;
  691.     Sprintf (n);
  692.     *sptr = '\0';
  693. }
  694.  
  695. Sprintf (n)
  696. {
  697.     int a;
  698.  
  699.     if (a = n/10)
  700.     Sprintf (a);
  701.     *sptr++ = n % 10 + '0';
  702. }
  703.  
  704. static char bell = ctrl('G');
  705.  
  706. strlen (s)
  707. char *s;
  708. {
  709.     register char *p;
  710.  
  711.     p = s;
  712.     while (*p++)
  713.     ;
  714.     return (p - s - 1);
  715. }
  716.  
  717. /* See whether the last component of the path name "path" is equal to the
  718. ** string "string"
  719. */
  720.  
  721. tailequ (path, string)
  722. char *path;
  723. register char *string;
  724. {
  725.     register char *tail;
  726.  
  727.     tail = path + strlen(path);
  728.     while (tail >= path)
  729.         if (*(--tail) == '/')
  730.             break;
  731.     ++tail;
  732.     while (*tail++ == *string++)
  733.         if (*tail == '\0')
  734.             return(1);
  735.     return(0);
  736. }
  737.  
  738. prompt (filename)
  739. char *filename;
  740. {
  741.     if (clreol)
  742.     cleareol ();
  743.     else if (promptlen > 0)
  744.     kill_line ();
  745.     if (!hard) {
  746.     promptlen = 8;
  747.     if (Senter && Sexit) {
  748.         tputs (Senter, 1, putch);
  749.         promptlen += (2 * soglitch);
  750.     }
  751.     if (clreol)
  752.         cleareol ();
  753.     pr("--More--");
  754.     if (filename != NULL) {
  755.         promptlen += printf ("(Next file: %s)", filename);
  756.     }
  757.     else if (!no_intty) {
  758.         promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
  759.     }
  760.     if (dum_opt) {
  761.         promptlen += pr("[Press space to continue, 'q' to quit.]");
  762.     }
  763.     if (Senter && Sexit)
  764.         tputs (Sexit, 1, putch);
  765.     if (clreol)
  766.         clreos ();
  767.     fflush(stdout);
  768.     }
  769.     else
  770.     write (2, &bell, 1);
  771.     inwait++;
  772. }
  773.  
  774. /*
  775. ** Get a logical line
  776. */
  777.  
  778. getline(f, length)
  779. register FILE *f;
  780. int *length;
  781. {
  782.     register int    c;
  783.     register char    *p;
  784.     register int    column;
  785.     static int        colflg;
  786.  
  787.     p = Line;
  788.     column = 0;
  789.     c = Getc (f);
  790.     if (colflg && c == '\n') {
  791.     Currline++;
  792.     c = Getc (f);
  793.     }
  794.     while (p < &Line[LINSIZ - 1]) {
  795.     if (c == EOF) {
  796.         if (p > Line) {
  797.         *p = '\0';
  798.         *length = p - Line;
  799.         return (column);
  800.         }
  801.         *length = p - Line;
  802.         return (EOF);
  803.     }
  804.     if (c == '\n') {
  805.         Currline++;
  806.         break;
  807.     }
  808.     *p++ = c;
  809.     if (c == '\t')
  810.         if (!hardtabs || column < promptlen && !hard) {
  811.         if (hardtabs && eraseln && !dumb) {
  812.             column = 1 + (column | 7);
  813.             tputs (eraseln, 1, putch);
  814.             promptlen = 0;
  815.         }
  816.         else {
  817.             for (--p; p < &Line[LINSIZ - 1];) {
  818.             *p++ = ' ';
  819.             if ((++column & 7) == 0)
  820.                 break;
  821.             }
  822.             if (column >= promptlen) promptlen = 0;
  823.         }
  824.         }
  825.         else
  826.         column = 1 + (column | 7);
  827.     else if (c == '\b' && column > 0)
  828.         column--;
  829.     else if (c == '\r')
  830.         column = 0;
  831.     else if (c == '\f' && stop_opt) {
  832.         p[-1] = '^';
  833.         *p++ = 'L';
  834.         column += 2;
  835.         Pause++;
  836.     }
  837.     else if (c == EOF) {
  838.         *length = p - Line;
  839.         return (column);
  840.     }
  841.     else if (c >= ' ' && c != RUBOUT)
  842.         column++;
  843.     if (column >= Mcol && fold_opt) break;
  844.     c = Getc (f);
  845.     }
  846.     if (column >= Mcol && Mcol > 0) {
  847.     if (!Wrap) {
  848.         *p++ = '\n';
  849.     }
  850.     }
  851.     colflg = column == Mcol && fold_opt;
  852.     if (colflg && eatnl && Wrap) {
  853.     *p++ = '\n'; /* simulate normal wrap */
  854.     }
  855.     *length = p - Line;
  856.     *p = 0;
  857.     return (column);
  858. }
  859.  
  860. /*
  861. ** Erase the rest of the prompt, assuming we are starting at column col.
  862. */
  863.  
  864. erase (col)
  865. register int col;
  866. {
  867.  
  868.     if (promptlen == 0)
  869.     return;
  870.     if (hard) {
  871.     putchar ('\n');
  872.     }
  873.     else {
  874.     if (col == 0)
  875.         putchar ('\r');
  876.     if (!dumb && eraseln)
  877.         tputs (eraseln, 1, putch);
  878.     else
  879.         for (col = promptlen - col; col > 0; col--)
  880.         putchar (' ');
  881.     }
  882.     promptlen = 0;
  883. }
  884.  
  885. /*
  886. ** Erase the current line entirely
  887. */
  888.  
  889. kill_line ()
  890. {
  891.     erase (0);
  892.     if (!eraseln || dumb) putchar ('\r');
  893. }
  894.  
  895. /*
  896.  * force clear to end of line
  897.  */
  898. cleareol()
  899. {
  900.     tputs(eraseln, 1, putch);
  901. }
  902.  
  903. clreos()
  904. {
  905.     tputs(EodClr, 1, putch);
  906. }
  907.  
  908. /*
  909. **  Print string and return number of characters
  910. */
  911.  
  912. pr(s1)
  913. char    *s1;
  914. {
  915.     register char    *s;
  916.     register char    c;
  917.  
  918.     for (s = s1; c = *s++; )
  919.     putchar(c);
  920.     return (s - s1 - 1);
  921. }
  922.  
  923.  
  924. /* Print a buffer of n characters */
  925.  
  926. prbuf (s, n)
  927. register char *s;
  928. register int n;
  929. {
  930.     register char c;            /* next output character */
  931.     register int state;            /* next output char's UL state */
  932. #define wouldul(s,n)    ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
  933.  
  934.     while (--n >= 0)
  935.     if (!ul_opt)
  936.         putchar (*s++);
  937.     else {
  938.         if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) {
  939.         s++;
  940.         continue;
  941.         }
  942.         if (state = wouldul(s, n)) {
  943.         c = (*s == '_')? s[2] : *s ;
  944.         n -= 2;
  945.         s += 3;
  946.         } else
  947.         c = *s++;
  948.         if (state != pstate) {
  949.         if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1))
  950.             state = 1;
  951.         else
  952.             tputs(state ? ULenter : ULexit, 1, putch);
  953.         }
  954.         if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0)
  955.             putchar(c);
  956.         if (state && *chUL) {
  957.         pr(chBS);
  958.         tputs(chUL, 1, putch);
  959.         }
  960.         pstate = state;
  961.     }
  962. }
  963.  
  964. /*
  965. **  Clear the screen
  966. */
  967.  
  968. doclear()
  969. {
  970.     if (Clear && !hard) {
  971.     tputs(Clear, 1, putch);
  972.  
  973.     /* Put out carriage return so that system doesn't
  974.     ** get confused by escape sequences when expanding tabs
  975.     */
  976.     putchar ('\r');
  977.     promptlen = 0;
  978.     }
  979. }
  980.  
  981. /*
  982.  * Go to home position
  983.  */
  984. home()
  985. {
  986.     tputs(Home,1,putch);
  987. }
  988.  
  989. static int lastcmd, lastarg, lastp;
  990. static int lastcolon;
  991. char shell_line[132];
  992.  
  993. /*
  994. ** Read a command and do it. A command consists of an optional integer
  995. ** argument followed by the command character.  Return the number of lines
  996. ** to display in the next screenful.  If there is nothing more to display
  997. ** in the current file, zero is returned.
  998. */
  999.  
  1000. command (filename, f)
  1001. char *filename;
  1002. register FILE *f;
  1003. {
  1004.     register int nlines;
  1005.     register int retval;
  1006.     register char c;
  1007.     char colonch;
  1008.     FILE *helpf;
  1009.     int done;
  1010.     char comchar, cmdbuf[80], *p;
  1011.  
  1012. #define ret(val) retval=val;done++;break
  1013.  
  1014.     done = 0;
  1015.     if (!errors)
  1016.     prompt (filename);
  1017.     else
  1018.     errors = 0;
  1019.     if (MBIT == RAW && slow_tty) {
  1020.     otty.sg_flags |= MBIT;
  1021.     stty(fileno(stderr), &otty);
  1022.     }
  1023.     for (;;) {
  1024.     nlines = number (&comchar);
  1025.     lastp = colonch = 0;
  1026.     if (comchar == '.') {    /* Repeat last command */
  1027.         lastp++;
  1028.         comchar = lastcmd;
  1029.         nlines = lastarg;
  1030.         if (lastcmd == ':')
  1031.             colonch = lastcolon;
  1032.     }
  1033.     lastcmd = comchar;
  1034.     lastarg = nlines;
  1035.     if (comchar == otty.sg_erase) {
  1036.         kill_line ();
  1037.         prompt (filename);
  1038.         continue;
  1039.     }
  1040.     switch (comchar) {
  1041.     case ':':
  1042.         retval = colon (filename, colonch, nlines);
  1043.         if (retval >= 0)
  1044.         done++;
  1045.         break;
  1046.     case 'b':
  1047.     case ctrl('B'):
  1048.         {
  1049.         register int initline;
  1050.  
  1051.         if (no_intty) {
  1052.             write(2, &bell, 1);
  1053.             return (-1);
  1054.         }
  1055.  
  1056.         if (nlines == 0) nlines++;
  1057.  
  1058.         putchar ('\r');
  1059.         erase (0);
  1060.         printf ("\n");
  1061.         if (clreol)
  1062.             cleareol ();
  1063.         printf ("...back %d page", nlines);
  1064.         if (nlines > 1)
  1065.             pr ("s\n");
  1066.         else
  1067.             pr ("\n");
  1068.  
  1069.         if (clreol)
  1070.             cleareol ();
  1071.         pr ("\n");
  1072.  
  1073.         initline = Currline - dlines * (nlines + 1);
  1074.         if (! noscroll)
  1075.             --initline;
  1076.         if (initline < 0) initline = 0;
  1077.         Fseek(f, 0L);
  1078.         Currline = 0;    /* skiplns() will make Currline correct */
  1079.         skiplns(initline, f);
  1080.         if (! noscroll) {
  1081.             ret(dlines + 1);
  1082.         }
  1083.         else {
  1084.             ret(dlines);
  1085.         }
  1086.         }
  1087.     case ' ':
  1088.     case 'z':
  1089.         if (nlines == 0) nlines = dlines;
  1090.         else if (comchar == 'z') dlines = nlines;
  1091.         ret (nlines);
  1092.     case 'd':
  1093.     case ctrl('D'):
  1094.         if (nlines != 0) nscroll = nlines;
  1095.         ret (nscroll);
  1096.     case 'q':
  1097.     case 'Q':
  1098.         end_it ();
  1099.     case 's':
  1100.     case 'f':
  1101.         if (nlines == 0) nlines++;
  1102.         if (comchar == 'f')
  1103.         nlines *= dlines;
  1104.         putchar ('\r');
  1105.         erase (0);
  1106.         printf ("\n");
  1107.         if (clreol)
  1108.         cleareol ();
  1109.         printf ("...skipping %d line", nlines);
  1110.         if (nlines > 1)
  1111.         pr ("s\n");
  1112.         else
  1113.         pr ("\n");
  1114.  
  1115.         if (clreol)
  1116.         cleareol ();
  1117.         pr ("\n");
  1118.  
  1119.         while (nlines > 0) {
  1120.         while ((c = Getc (f)) != '\n')
  1121.             if (c == EOF) {
  1122.             retval = 0;
  1123.             done++;
  1124.             goto endsw;
  1125.             }
  1126.             Currline++;
  1127.             nlines--;
  1128.         }
  1129.         ret (dlines);
  1130.     case '\n':
  1131.         if (nlines != 0)
  1132.         dlines = nlines;
  1133.         else
  1134.         nlines = 1;
  1135.         ret (nlines);
  1136.     case '\f':
  1137.         if (!no_intty) {
  1138.         doclear ();
  1139.         Fseek (f, screen_start.chrctr);
  1140.         Currline = screen_start.line;
  1141.         ret (dlines);
  1142.         }
  1143.         else {
  1144.         write (2, &bell, 1);
  1145.         break;
  1146.         }
  1147.     case '\'':
  1148.         if (!no_intty) {
  1149.         kill_line ();
  1150.         pr ("\n***Back***\n\n");
  1151.         Fseek (f, context.chrctr);
  1152.         Currline = context.line;
  1153.         ret (dlines);
  1154.         }
  1155.         else {
  1156.         write (2, &bell, 1);
  1157.         break;
  1158.         }
  1159.     case '=':
  1160.         kill_line ();
  1161.         promptlen = printd (Currline);
  1162.         fflush (stdout);
  1163.         break;
  1164.     case 'n':
  1165.         lastp++;
  1166.     case '/':
  1167.         if (nlines == 0) nlines++;
  1168.         kill_line ();
  1169.         pr ("/");
  1170.         promptlen = 1;
  1171.         fflush (stdout);
  1172.         if (lastp) {
  1173.         write (2,"\r", 1);
  1174.         search (NULL, f, nlines);    /* Use previous r.e. */
  1175.         }
  1176.         else {
  1177.         ttyin (cmdbuf, 78, '/');
  1178.         write (2, "\r", 1);
  1179.         search (cmdbuf, f, nlines);
  1180.         }
  1181.         ret (dlines-1);
  1182.     case '!':
  1183.         do_shell (filename);
  1184.         break;
  1185.     case '?':
  1186.     case 'h':
  1187.         if ((helpf = fopen (HELPFILE, "r")) == NULL)
  1188.         error ("Can't open help file");
  1189.         if (noscroll) doclear ();
  1190.         copy_file (helpf);
  1191.         fclose (helpf);
  1192.         prompt (filename);
  1193.         break;
  1194.     case 'v':    /* This case should go right before default */
  1195.         if (!no_intty) {
  1196.         kill_line ();
  1197.         cmdbuf[0] = '+';
  1198.         scanstr (Currline - dlines < 0 ? 0
  1199.                 : Currline - (dlines + 1) / 2, &cmdbuf[1]);
  1200.         pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
  1201.         execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
  1202.         break;
  1203.         }
  1204.     default:
  1205.         if (dum_opt) {
  1206.            kill_line ();
  1207.         if (Senter && Sexit) {
  1208.             tputs (Senter, 1, putch);
  1209.             promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch);
  1210.             tputs (Sexit, 1, putch);
  1211.         }
  1212.         else
  1213.             promptlen = pr ("[Press 'h' for instructions.]");
  1214.         fflush (stdout);
  1215.         }
  1216.         else
  1217.         write (2, &bell, 1);
  1218.         break;
  1219.     }
  1220.     if (done) break;
  1221.     }
  1222.     putchar ('\r');
  1223. endsw:
  1224.     inwait = 0;
  1225.     notell++;
  1226.     if (MBIT == RAW && slow_tty) {
  1227.     otty.sg_flags &= ~MBIT;
  1228.     stty(fileno(stderr), &otty);
  1229.     }
  1230.     return (retval);
  1231. }
  1232.  
  1233. char ch;
  1234.  
  1235. /*
  1236.  * Execute a colon-prefixed command.
  1237.  * Returns <0 if not a command that should cause
  1238.  * more of the file to be printed.
  1239.  */
  1240.  
  1241. colon (filename, cmd, nlines)
  1242. char *filename;
  1243. int cmd;
  1244. int nlines;
  1245. {
  1246.     if (cmd == 0)
  1247.         ch = readch ();
  1248.     else
  1249.         ch = cmd;
  1250.     lastcolon = ch;
  1251.     switch (ch) {
  1252.     case 'f':
  1253.         kill_line ();
  1254.         if (!no_intty)
  1255.             promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline);
  1256.         else
  1257.             promptlen = printf ("[Not a file] line %d", Currline);
  1258.         fflush (stdout);
  1259.         return (-1);
  1260.     case 'n':
  1261.         if (nlines == 0) {
  1262.             if (fnum >= nfiles - 1)
  1263.                 end_it ();
  1264.             nlines++;
  1265.         }
  1266.         putchar ('\r');
  1267.         erase (0);
  1268.         skipf (nlines);
  1269.         return (0);
  1270.     case 'p':
  1271.         if (no_intty) {
  1272.             write (2, &bell, 1);
  1273.             return (-1);
  1274.         }
  1275.         putchar ('\r');
  1276.         erase (0);
  1277.         if (nlines == 0)
  1278.             nlines++;
  1279.         skipf (-nlines);
  1280.         return (0);
  1281.     case '!':
  1282.         do_shell (filename);
  1283.         return (-1);
  1284.     case 'q':
  1285.     case 'Q':
  1286.         end_it ();
  1287.     default:
  1288.         write (2, &bell, 1);
  1289.         return (-1);
  1290.     }
  1291. }
  1292.  
  1293. /*
  1294. ** Read a decimal number from the terminal. Set cmd to the non-digit which
  1295. ** terminates the number.
  1296. */
  1297.  
  1298. number(cmd)
  1299. char *cmd;
  1300. {
  1301.     register int i;
  1302.  
  1303.     i = 0; ch = otty.sg_kill;
  1304.     for (;;) {
  1305.         ch = readch ();
  1306.         if (ch >= '0' && ch <= '9')
  1307.             i = i*10 + ch - '0';
  1308.         else if (ch == otty.sg_kill)
  1309.             i = 0;
  1310.         else {
  1311.             *cmd = ch;
  1312.             break;
  1313.         }
  1314.     }
  1315.     return (i);
  1316. }
  1317.  
  1318. do_shell (filename)
  1319. char *filename;
  1320. {
  1321.     char cmdbuf[80];
  1322.  
  1323.     kill_line ();
  1324.     pr ("!");
  1325.     fflush (stdout);
  1326.     promptlen = 1;
  1327.     if (lastp)
  1328.         pr (shell_line);
  1329.     else {
  1330.         ttyin (cmdbuf, 78, '!');
  1331.         if (expand (shell_line, cmdbuf)) {
  1332.             kill_line ();
  1333.             promptlen = printf ("!%s", shell_line);
  1334.         }
  1335.     }
  1336.     fflush (stdout);
  1337.     write (2, "\n", 1);
  1338.     promptlen = 0;
  1339.     shellp = 1;
  1340.     execute (filename, shell, shell, "-c", shell_line, 0);
  1341. }
  1342.  
  1343. /*
  1344. ** Search for nth ocurrence of regular expression contained in buf in the file
  1345. */
  1346.  
  1347. search (buf, file, n)
  1348. char buf[];
  1349. FILE *file;
  1350. register int n;
  1351. {
  1352.     long startline = Ftell (file);
  1353.     register long line1 = startline;
  1354.     register long line2 = startline;
  1355.     register long line3 = startline;
  1356.     register int lncount;
  1357.     int saveln, rv, re_exec();
  1358.     char *s, *re_comp();
  1359.  
  1360.     context.line = saveln = Currline;
  1361.     context.chrctr = startline;
  1362.     lncount = 0;
  1363.     if ((s = re_comp (buf)) != 0)
  1364.     error (s);
  1365.     while (!feof (file)) {
  1366.     line3 = line2;
  1367.     line2 = line1;
  1368.     line1 = Ftell (file);
  1369.     rdline (file);
  1370.     lncount++;
  1371.     if ((rv = re_exec (Line)) == 1)
  1372.         if (--n == 0) {
  1373.             if (lncount > 3 || (lncount > 1 && no_intty))
  1374.             {
  1375.             pr ("\n");
  1376.             if (clreol)
  1377.                 cleareol ();
  1378.             pr("...skipping\n");
  1379.             }
  1380.             if (!no_intty) {
  1381.             Currline -= (lncount >= 3 ? 3 : lncount);
  1382.             Fseek (file, line3);
  1383.             if (noscroll)
  1384.                 if (clreol) {
  1385.                 home ();
  1386.                 cleareol ();
  1387.                 }
  1388.                 else
  1389.                 doclear ();
  1390.             }
  1391.             else {
  1392.             kill_line ();
  1393.             if (noscroll)
  1394.                 if (clreol) {
  1395.                     home ();
  1396.                     cleareol ();
  1397.                 }
  1398.                 else
  1399.                 doclear ();
  1400.             pr (Line);
  1401.             putchar ('\n');
  1402.             }
  1403.             break;
  1404.         }
  1405.     else if (rv == -1)
  1406.         error ("Regular expression botch");
  1407.     }
  1408.     if (feof (file)) {
  1409.     if (!no_intty) {
  1410.         Currline = saveln;
  1411.         Fseek (file, startline);
  1412.     }
  1413.     else {
  1414.         pr ("\nPattern not found\n");
  1415.         end_it ();
  1416.     }
  1417.     error ("Pattern not found");
  1418.     }
  1419. }
  1420.  
  1421. /*VARARGS2*/
  1422. execute (va_alist)
  1423. va_dcl
  1424. {
  1425.     int id;
  1426.     int n;
  1427.     char *filename;
  1428.     char *cmd;
  1429.     va_list argp;
  1430.  
  1431.     va_start(argp);
  1432.     filename = va_arg(argp, char *);
  1433.     cmd = va_arg(argp, char *);
  1434.  
  1435.     fflush (stdout);
  1436.     reset_tty ();
  1437.     for (n = 10; (id = fork ()) < 0 && n > 0; n--)
  1438.         sleep (5);
  1439.     if (id == 0) {
  1440.         if (!isatty(0)) {
  1441.         close(0);
  1442.         open("/dev/tty", 0);
  1443.         }
  1444.  
  1445.         execv (cmd, argp);
  1446.         write (2, "exec failed\n", 12);
  1447.         exit (1);
  1448.     }
  1449.     if (id > 0) {
  1450.         signal (SIGINT, SIG_IGN);
  1451.         signal (SIGQUIT, SIG_IGN);
  1452.         if (catch_susp)
  1453.         signal(SIGTSTP, SIG_DFL);
  1454.         while (wait(0) > 0);
  1455.         signal (SIGINT, end_it);
  1456.         signal (SIGQUIT, onquit);
  1457.         if (catch_susp)
  1458.         signal(SIGTSTP, onsusp);
  1459.     } else
  1460.         write(2, "can't fork\n", 11);
  1461.     set_tty ();
  1462.     pr ("------------------------\n");
  1463.     prompt (filename);
  1464.     va_end(argp);    /* balance {}'s for some UNIX's */
  1465. }
  1466. /*
  1467. ** Skip n lines in the file f
  1468. */
  1469.  
  1470. skiplns (n, f)
  1471. register int n;
  1472. register FILE *f;
  1473. {
  1474.     register char c;
  1475.  
  1476.     while (n > 0) {
  1477.     while ((c = Getc (f)) != '\n')
  1478.         if (c == EOF)
  1479.         return;
  1480.         n--;
  1481.         Currline++;
  1482.     }
  1483. }
  1484.  
  1485. /*
  1486. ** Skip nskip files in the file list (from the command line). Nskip may be
  1487. ** negative.
  1488. */
  1489.  
  1490. skipf (nskip)
  1491. register int nskip;
  1492. {
  1493.     if (nskip == 0) return;
  1494.     if (nskip > 0) {
  1495.     if (fnum + nskip > nfiles - 1)
  1496.         nskip = nfiles - fnum - 1;
  1497.     }
  1498.     else if (within)
  1499.     ++fnum;
  1500.     fnum += nskip;
  1501.     if (fnum < 0)
  1502.     fnum = 0;
  1503.     pr ("\n...Skipping ");
  1504.     pr ("\n");
  1505.     if (clreol)
  1506.     cleareol ();
  1507.     pr ("...Skipping ");
  1508.     pr (nskip > 0 ? "to file " : "back to file ");
  1509.     pr (fnames[fnum]);
  1510.     pr ("\n");
  1511.     if (clreol)
  1512.     cleareol ();
  1513.     pr ("\n");
  1514.     --fnum;
  1515. }
  1516.  
  1517. /*----------------------------- Terminal I/O -------------------------------*/
  1518.  
  1519. initterm ()
  1520. {
  1521.     char    buf[TBUFSIZ];
  1522.     static char    clearbuf[TBUFSIZ];
  1523.     char    *clearptr, *padstr;
  1524.     int        ldisc;
  1525.     int        lmode;
  1526.     char    *term;
  1527.     int        tgrp;
  1528.     struct winsize win;
  1529.  
  1530. retry:
  1531.     if (!(no_tty = gtty(fileno(stdout), &otty))) {
  1532.     if (ioctl(fileno(stdout), TIOCLGET, &lmode) >= 0) {
  1533.         docrterase = ((lmode & LCRTERA) != 0);
  1534.         docrtkill = ((lmode & LCRTKIL) != 0);
  1535.         /*
  1536.          * Wait until we're in the foreground before we save the
  1537.          * the terminal modes.
  1538.          */
  1539.         if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
  1540.         perror("TIOCGPGRP");
  1541.         exit(1);
  1542.         }
  1543.         if (tgrp != getpgrp(0)) {
  1544.         kill(0, SIGTTOU);
  1545.         goto retry;
  1546.         }
  1547.     }
  1548.     if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) {
  1549.         dumb++; ul_opt = 0;
  1550.     }
  1551.     else {
  1552.         if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
  1553.         Lpp = tgetnum("li");
  1554.         Mcol = tgetnum("co");
  1555.         } else {
  1556.         if ((Lpp = win.ws_row) == 0)
  1557.             Lpp = tgetnum("li");
  1558.         if ((Mcol = win.ws_col) == 0)
  1559.             Mcol = tgetnum("co");
  1560.         }
  1561.         if ((Lpp <= 0) || tgetflag("hc")) {
  1562.         hard++;    /* Hard copy terminal */
  1563.         Lpp = 24;
  1564.         }
  1565.         if (tgetflag("xn"))
  1566.         eatnl++; /* Eat newline at last column + 1; dec, concept */
  1567.         if (Mcol <= 0)
  1568.         Mcol = 80;
  1569.  
  1570.         if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
  1571.         noscroll++;
  1572.         Wrap = tgetflag("am");
  1573.         bad_so = tgetflag ("xs");
  1574.         clearptr = clearbuf;
  1575.         eraseln = tgetstr("ce",&clearptr);
  1576.         Clear = tgetstr("cl", &clearptr);
  1577.         Senter = tgetstr("so", &clearptr);
  1578.         Sexit = tgetstr("se", &clearptr);
  1579.         if ((soglitch = tgetnum("sg")) < 0)
  1580.         soglitch = 0;
  1581.  
  1582.         /*
  1583.          *  Set up for underlining:  some terminals don't need it;
  1584.          *  others have start/stop sequences, still others have an
  1585.          *  underline char sequence which is assumed to move the
  1586.          *  cursor forward one character.  If underline sequence
  1587.          *  isn't available, settle for standout sequence.
  1588.          */
  1589.  
  1590.         if (tgetflag("ul") || tgetflag("os"))
  1591.         ul_opt = 0;
  1592.         if ((chUL = tgetstr("uc", &clearptr)) == NULL )
  1593.         chUL = "";
  1594.         if (((ULenter = tgetstr("us", &clearptr)) == NULL ||
  1595.              (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) {
  1596.             if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) {
  1597.             ULenter = "";
  1598.             ULexit = "";
  1599.         } else
  1600.             ulglitch = soglitch;
  1601.         } else {
  1602.         if ((ulglitch = tgetnum("ug")) < 0)
  1603.             ulglitch = 0;
  1604.         }
  1605.  
  1606.         if (padstr = tgetstr("pc", &clearptr))
  1607.         PC = *padstr;
  1608.         Home = tgetstr("ho",&clearptr);
  1609.         if (Home == 0 || *Home == '\0')
  1610.         {
  1611.         if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
  1612.             strcpy(cursorhome, tgoto(cursorm, 0, 0));
  1613.             Home = cursorhome;
  1614.            }
  1615.         }
  1616.         EodClr = tgetstr("cd", &clearptr);
  1617.         if ((chBS = tgetstr("bc", &clearptr)) == NULL)
  1618.         chBS = "\b";
  1619.  
  1620.     }
  1621.     if ((shell = getenv("SHELL")) == NULL)
  1622.         shell = "/bin/sh";
  1623.     }
  1624.     no_intty = gtty(fileno(stdin), &otty);
  1625.     gtty(fileno(stderr), &otty);
  1626.     savetty = otty;
  1627.     ospeed = otty.sg_ospeed;
  1628.     slow_tty = ospeed < B1200;
  1629.     hardtabs = (otty.sg_flags & TBDELAY) != XTABS;
  1630.     if (!no_tty) {
  1631.     otty.sg_flags &= ~ECHO;
  1632.     if (MBIT == CBREAK || !slow_tty)
  1633.         otty.sg_flags |= MBIT;
  1634.     }
  1635. }
  1636.  
  1637. readch ()
  1638. {
  1639.     char ch;
  1640.     extern int errno;
  1641.  
  1642.     errno = 0;
  1643.     if (read (2, &ch, 1) <= 0)
  1644.         if (errno != EINTR)
  1645.             end_it();
  1646.         else
  1647.             ch = otty.sg_kill;
  1648.     return (ch);
  1649. }
  1650.  
  1651. static char BS = '\b';
  1652. static char *BSB = "\b \b";
  1653. static char CARAT = '^';
  1654. #define ERASEONECHAR \
  1655.     if (docrterase) \
  1656.     write (2, BSB, sizeof(BSB)); \
  1657.     else \
  1658.     write (2, &BS, sizeof(BS));
  1659.  
  1660. ttyin (buf, nmax, pchar)
  1661. char buf[];
  1662. register int nmax;
  1663. char pchar;
  1664. {
  1665.     register char *sptr;
  1666.     register char ch;
  1667.     register int slash = 0;
  1668.     int    maxlen;
  1669.     char cbuf;
  1670.  
  1671.     sptr = buf;
  1672.     maxlen = 0;
  1673.     while (sptr - buf < nmax) {
  1674.     if (promptlen > maxlen) maxlen = promptlen;
  1675.     ch = readch ();
  1676.     if (ch == '\\') {
  1677.         slash++;
  1678.     }
  1679.     else if ((ch == otty.sg_erase) && !slash) {
  1680.         if (sptr > buf) {
  1681.         --promptlen;
  1682.         ERASEONECHAR
  1683.         --sptr;
  1684.         if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
  1685.             --promptlen;
  1686.             ERASEONECHAR
  1687.         }
  1688.         continue;
  1689.         }
  1690.         else {
  1691.         if (!eraseln) promptlen = maxlen;
  1692.         longjmp (restore, 1);
  1693.         }
  1694.     }
  1695.     else if ((ch == otty.sg_kill) && !slash) {
  1696.         if (hard) {
  1697.         show (ch);
  1698.         putchar ('\n');
  1699.         putchar (pchar);
  1700.         }
  1701.         else {
  1702.         putchar ('\r');
  1703.         putchar (pchar);
  1704.         if (eraseln)
  1705.             erase (1);
  1706.         else if (docrtkill)
  1707.             while (promptlen-- > 1)
  1708.             write (2, BSB, sizeof(BSB));
  1709.         promptlen = 1;
  1710.         }
  1711.         sptr = buf;
  1712.         fflush (stdout);
  1713.         continue;
  1714.     }
  1715.     if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
  1716.         ERASEONECHAR
  1717.         --sptr;
  1718.     }
  1719.     if (ch != '\\')
  1720.         slash = 0;
  1721.     *sptr++ = ch;
  1722.     if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
  1723.         ch += ch == RUBOUT ? -0100 : 0100;
  1724.         write (2, &CARAT, 1);
  1725.         promptlen++;
  1726.     }
  1727.     cbuf = ch;
  1728.     if (ch != '\n' && ch != ESC) {
  1729.         write (2, &cbuf, 1);
  1730.         promptlen++;
  1731.     }
  1732.     else
  1733.         break;
  1734.     }
  1735.     *--sptr = '\0';
  1736.     if (!eraseln) promptlen = maxlen;
  1737.     if (sptr - buf >= nmax - 1)
  1738.     error ("Line too long");
  1739. }
  1740.  
  1741. expand (outbuf, inbuf)
  1742. char *outbuf;
  1743. char *inbuf;
  1744. {
  1745.     register char *instr;
  1746.     register char *outstr;
  1747.     register char ch;
  1748.     char temp[200];
  1749.     int changed = 0;
  1750.  
  1751.     instr = inbuf;
  1752.     outstr = temp;
  1753.     while ((ch = *instr++) != '\0')
  1754.     switch (ch) {
  1755.     case '%':
  1756.         if (!no_intty) {
  1757.         strcpy (outstr, fnames[fnum]);
  1758.         outstr += strlen (fnames[fnum]);
  1759.         changed++;
  1760.         }
  1761.         else
  1762.         *outstr++ = ch;
  1763.         break;
  1764.     case '!':
  1765.         if (!shellp)
  1766.         error ("No previous command to substitute for");
  1767.         strcpy (outstr, shell_line);
  1768.         outstr += strlen (shell_line);
  1769.         changed++;
  1770.         break;
  1771.     case '\\':
  1772.         if (*instr == '%' || *instr == '!') {
  1773.         *outstr++ = *instr++;
  1774.         break;
  1775.         }
  1776.     default:
  1777.         *outstr++ = ch;
  1778.     }
  1779.     *outstr++ = '\0';
  1780.     strcpy (outbuf, temp);
  1781.     return (changed);
  1782. }
  1783.  
  1784. show (ch)
  1785. register char ch;
  1786. {
  1787.     char cbuf;
  1788.  
  1789.     if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
  1790.     ch += ch == RUBOUT ? -0100 : 0100;
  1791.     write (2, &CARAT, 1);
  1792.     promptlen++;
  1793.     }
  1794.     cbuf = ch;
  1795.     write (2, &cbuf, 1);
  1796.     promptlen++;
  1797. }
  1798.  
  1799. error (mess)
  1800. char *mess;
  1801. {
  1802.     if (clreol)
  1803.     cleareol ();
  1804.     else
  1805.     kill_line ();
  1806.     promptlen += strlen (mess);
  1807.     if (Senter && Sexit) {
  1808.     tputs (Senter, 1, putch);
  1809.     pr(mess);
  1810.     tputs (Sexit, 1, putch);
  1811.     }
  1812.     else
  1813.     pr (mess);
  1814.     fflush(stdout);
  1815.     errors++;
  1816.     longjmp (restore, 1);
  1817. }
  1818.  
  1819.  
  1820. set_tty ()
  1821. {
  1822.     otty.sg_flags |= MBIT;
  1823.     otty.sg_flags &= ~ECHO;
  1824.     stty(fileno(stderr), &otty);
  1825. }
  1826.  
  1827. reset_tty ()
  1828. {
  1829.     if (no_tty)
  1830.     return;
  1831.     if (pstate) {
  1832.     tputs(ULexit, 1, putch);
  1833.     fflush(stdout);
  1834.     pstate = 0;
  1835.     }
  1836.     otty.sg_flags |= ECHO;
  1837.     otty.sg_flags &= ~MBIT;
  1838.     stty(fileno(stderr), &savetty);
  1839. }
  1840.  
  1841. rdline (f)
  1842. register FILE *f;
  1843. {
  1844.     register char c;
  1845.     register char *p;
  1846.  
  1847.     p = Line;
  1848.     while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
  1849.     *p++ = c;
  1850.     if (c == '\n')
  1851.     Currline++;
  1852.     *p = '\0';
  1853. }
  1854.  
  1855. /* Come here when we get a suspend signal from the terminal */
  1856.  
  1857. onsusp ()
  1858. {
  1859.     /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
  1860.     signal(SIGTTOU, SIG_IGN);
  1861.     reset_tty ();
  1862.     fflush (stdout);
  1863.     signal(SIGTTOU, SIG_DFL);
  1864.     /* Send the TSTP signal to suspend our process group */
  1865.     signal(SIGTSTP, SIG_DFL);
  1866.     sigsetmask(0);
  1867.     kill (0, SIGTSTP);
  1868.     /* Pause for station break */
  1869.  
  1870.     /* We're back */
  1871.     signal (SIGTSTP, onsusp);
  1872.     set_tty ();
  1873.     if (inwait)
  1874.         longjmp (restore);
  1875. }
  1876. @
  1877.  
  1878.  
  1879. 1.4
  1880. log
  1881. @Fixed so that if ioctl fails, more will still work.
  1882. This lets it work on the console
  1883. @
  1884. text
  1885. @d1379 1
  1886. a1379 3
  1887. execute (filename, cmd, va_alist)
  1888. char *filename;
  1889. char *cmd;
  1890. d1384 2
  1891. d1388 4
  1892. d1401 1
  1893. a1401 1
  1894.         va_start(argp);
  1895. a1404 1
  1896.         va_end(argp);    /* balance {}'s for some UNIX's */
  1897. d1421 1
  1898. @
  1899.  
  1900.  
  1901. 1.3
  1902. log
  1903. @Patched printf routine to work on SPUR.
  1904. @
  1905. text
  1906. @d1485 15
  1907. a1499 17
  1908.     if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) {
  1909.         perror("TIOCLGET");
  1910.         exit(1);
  1911.     }
  1912.     docrterase = ((lmode & LCRTERA) != 0);
  1913.     docrtkill = ((lmode & LCRTKIL) != 0);
  1914.     /*
  1915.      * Wait until we're in the foreground before we save the
  1916.      * the terminal modes.
  1917.      */
  1918.     if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
  1919.         perror("TIOCGPGRP");
  1920.         exit(1);
  1921.     }
  1922.     if (tgrp != getpgrp(0)) {
  1923.         kill(0, SIGTTOU);
  1924.         goto retry;
  1925. @
  1926.  
  1927.  
  1928. 1.2
  1929. log
  1930. @Miscellaneous changes to work with Sprite (different file locations, etc.).
  1931. @
  1932. text
  1933. @d582 1
  1934. a582 2
  1935. printf (fmt, va_alist)
  1936. register char *fmt;
  1937. d588 1
  1938. d592 1
  1939. @
  1940.  
  1941.  
  1942. 1.1
  1943. log
  1944. @Initial revision
  1945. @
  1946. text
  1947. @d44 2
  1948. a45 2
  1949. #define HELPFILE    "/usr/lib/more.help"
  1950. #define VI        "/usr/ucb/vi"
  1951. d118 3
  1952. d122 2
  1953. a1365 1
  1954.         file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */
  1955. @
  1956.